package com.ddh.codeduck.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codeduck.pojo.dto.CodeDuckTagDTO;
import com.codeduck.pojo.entity.CodeDuckQuestionCategory;
import com.codeduck.pojo.entity.CodeDuckQuestionCategoryTag;
import com.codeduck.pojo.entity.CodeDuckTag;
import com.ddh.codeduck.mapper.CodeDuckTagMapper;
import com.codeduck.pojo.req.CodeDuckTagPageReq;
import com.ddh.codeduck.service.ICodeDuckQuestionCategoryService;
import com.ddh.codeduck.service.ICodeDuckQuestionCategoryTagService;
import com.ddh.codeduck.service.ICodeDuckTagService;
import com.ddhcodeduck.common.exception.BusinessException;
import com.ddhcodeduck.common.exception.ErrorCode;
import com.ddhcodeduck.common.utils.UserContextHolder;
import com.codeduck.pojo.vo.CodeDuckTagVO;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

/**
 * <p>
 * 标签表 服务实现类
 * </p>
 *
 * @author ddh
 * @since 2021-03-09
 */
@Service
@Slf4j
public class CodeDuckTagServiceImpl extends ServiceImpl<CodeDuckTagMapper, CodeDuckTag> implements ICodeDuckTagService {
    @Lazy
    @Resource
    private ICodeDuckQuestionCategoryService codeDuckQuestionCategoryService;

    @Resource
    private ICodeDuckQuestionCategoryTagService codeDuckQuestionCategoryTagService;

    @Resource(name = "taskExecutor")
    private Executor taskExecutor;

    /**
     * 根据标签idList查询题目分类
     *
     * @param codeDuckTagDTO
     * @return
     */
    @Override
    public CodeDuckTagVO listQuestionCategory(CodeDuckTagDTO codeDuckTagDTO) {
        //根据标签id查询标签
        CodeDuckTag codeDuckTag = getById(codeDuckTagDTO.getId());
        CodeDuckTagVO codeDuckTagVO = new CodeDuckTagVO();
        BeanUtils.copyProperties(codeDuckTag, codeDuckTagVO);
        String tagId = codeDuckTagDTO.getId();
        LambdaQueryWrapper<CodeDuckQuestionCategoryTag> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(CodeDuckQuestionCategoryTag::getTagId, tagId);
        List<CodeDuckQuestionCategoryTag> codeDuckQuestionCategoryTagList = codeDuckQuestionCategoryTagService.list(queryWrapper);
        List<String> questionCategoryIdList = codeDuckQuestionCategoryTagList.stream()
                .map(CodeDuckQuestionCategoryTag::getCategoryId)
                .collect(Collectors.toList());
        //根据分类id查询所有题目分类
        List<CodeDuckQuestionCategory> questionCategoryList = codeDuckQuestionCategoryService
                .listByIds(questionCategoryIdList);
        List<CodeDuckQuestionCategory> questionCategoryListVO = questionCategoryList
                .stream()
                .map(questionCategory -> {
                    CodeDuckQuestionCategory questionCategoryVO = new CodeDuckQuestionCategory();
                    BeanUtils.copyProperties(questionCategory, questionCategoryVO);
                    return questionCategoryVO;
                })
                .collect(Collectors.toList());
        codeDuckTagVO.setQuestionCategorieList(questionCategoryListVO);
        return codeDuckTagVO;
    }

    /**
     * 查询所有标签及其题目分类
     *
     * @return
     */
    @Async
    public CompletableFuture<List<CodeDuckQuestionCategory>> asyncGetQuestionCategories(String tagId) {
        return CompletableFuture.supplyAsync(() -> {
            log.info("异步查询线程: {}, 标签ID: {}", Thread.currentThread().getName(), tagId);
            return getQuestionCategoriesByTagId(tagId);
        }, taskExecutor); // 直接使用注入的线程池
    }


    @Override
    @SneakyThrows
    public List<CodeDuckTagVO> listAndQuestionCategory() {
        LambdaQueryWrapper<CodeDuckTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(CodeDuckTag::getSort);
        queryWrapper.and(wrapper -> wrapper
                .isNull(CodeDuckTag::getParentId)
                .or()
                .eq(CodeDuckTag::getParentId, "")
        );
        List<CodeDuckTag> codeDuckTagList = this.list(queryWrapper);

        // 创建异步任务列表
        List<CompletableFuture<CodeDuckTagVO>> futures = codeDuckTagList.stream()
                .map(tag -> {
                    CodeDuckTagVO vo = new CodeDuckTagVO();
                    BeanUtils.copyProperties(tag, vo);
                    return asyncGetQuestionCategories(tag.getId())
                            .thenApply(categories -> {
                                vo.setQuestionCategorieList(categories);
                                return vo;
                            });
                })
                .collect(Collectors.toList());

        // 等待所有任务完成
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                futures.toArray(new CompletableFuture[0])
        );

        return allFutures.thenApply(v ->
                futures.stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList())
        ).get();
    }

    /**
     * 查询标签列表
     *
     * @param codeDuckTagPageReq
     * @return
     */
    @Override
    public IPage<CodeDuckTagVO> listTagList(CodeDuckTagPageReq codeDuckTagPageReq) {
        LambdaQueryWrapper<CodeDuckTag> queryWrapper = new LambdaQueryWrapper<>();
        if (codeDuckTagPageReq.getName() != null) {
            queryWrapper.like(CodeDuckTag::getName, codeDuckTagPageReq.getName());
        }
        // 只查询 parentId = null 的一级标签
        // 查询 parentId 为 null 或者 空字符串 的一级标签
        queryWrapper.and(wrapper -> wrapper
                .isNull(CodeDuckTag::getParentId)
                .or()
                .eq(CodeDuckTag::getParentId, "")
        );

        if ("desc".equals(codeDuckTagPageReq.getSortOrder())) {
            queryWrapper.orderByDesc(CodeDuckTag::getSort);
        } else if ("asc".equals(codeDuckTagPageReq.getSortOrder())) {
            queryWrapper.orderByAsc(CodeDuckTag::getSort);
        }

        IPage<CodeDuckTag> tagPage;
        if (codeDuckTagPageReq.getPageSize() == null || codeDuckTagPageReq.getCurrent() == null) {
            List<CodeDuckTag> tagList = list(queryWrapper);
            tagPage = new Page<CodeDuckTag>()
                    .setRecords(tagList)
                    .setSize(tagList.size())
                    .setCurrent(1)
                    .setTotal(tagList.size());
        } else {
            tagPage = page(new Page<>(codeDuckTagPageReq.getCurrent(), codeDuckTagPageReq.getPageSize()), queryWrapper);
        }

        // 转换并填充子标签
        return tagPage.convert(tag -> {
            CodeDuckTagVO tagVO = new CodeDuckTagVO();
            BeanUtils.copyProperties(tag, tagVO);
            // 查询 parentId 等于当前 tag.id 的子标签（即该一级标签下的所有子标签）
            LambdaQueryWrapper<CodeDuckTag> childQueryWrapper = new LambdaQueryWrapper<>();
            childQueryWrapper.eq(CodeDuckTag::getParentId, tag.getId());
            List<CodeDuckTag> children = list(childQueryWrapper);
            tagVO.setSecondCodeDuckTagList(children); // 设置子标签
            return tagVO;
        });
    }


    /**
     * 保存或更新标签
     *
     * @param codeDuckTagDTO
     * @return
     */
    @Override
    public Boolean saveOrUpdateTag(CodeDuckTagDTO codeDuckTagDTO) {
        if (codeDuckTagDTO.getId() == null) {
            //新增
            CodeDuckTag codeDuckTag = new CodeDuckTag();
            BeanUtils.copyProperties(codeDuckTagDTO, codeDuckTag);
            codeDuckTag.setCreatedBy(UserContextHolder.getUserId());
            codeDuckTag.setCreatedAt(LocalDateTime.now());
            return save(codeDuckTag);
        } else {
            //修改
            CodeDuckTag codeDuckTag = new CodeDuckTag();
            BeanUtils.copyProperties(codeDuckTagDTO, codeDuckTag);
            codeDuckTag.setCreatedBy(UserContextHolder.getUserId());
            codeDuckTag.setUpdatedAt(LocalDateTime.now());
            return updateById(codeDuckTag);
        }
    }

    @Override
    public Boolean removeBatchByIdsService(List<String> tagIdList) {
        //查询该id下有没有题目分类
        LambdaQueryWrapper<CodeDuckQuestionCategoryTag> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CodeDuckQuestionCategoryTag::getTagId, tagIdList);
        List<CodeDuckQuestionCategoryTag> codeDuckQuestionCategoryTagList = codeDuckQuestionCategoryTagService.list(queryWrapper);
        if (codeDuckQuestionCategoryTagList.size() > 0) {
            //有题目分类，不能删除
            throw new BusinessException(ErrorCode.TAG_HAS_QUESTION_CATEGORY_ERROR);
        }
        //如果没有关联的题目分类可以直接删除
        return removeBatchByIds(tagIdList);
    }

    /**
     * 根据标签ID查询题目分类
     *
     * @param tagId 标签ID
     * @return 题目分类列表
     */
    private List<CodeDuckQuestionCategory> getQuestionCategoriesByTagId(String tagId) {
        // 根据标签ID查询关联表
        LambdaQueryWrapper<CodeDuckQuestionCategoryTag> categoryTagQueryWrapper = new LambdaQueryWrapper<>();
        categoryTagQueryWrapper.eq(CodeDuckQuestionCategoryTag::getTagId, tagId);
        List<CodeDuckQuestionCategoryTag> categoryTagList = codeDuckQuestionCategoryTagService.list(categoryTagQueryWrapper);

        // 提取所有的 categoryId
        List<String> categoryIdList = categoryTagList.stream()
                .map(CodeDuckQuestionCategoryTag::getCategoryId)
                .distinct()
                .collect(Collectors.toList());

        // 如果 categoryIdList 为空，直接返回空列表
        if (categoryIdList.isEmpty()) {
            return Collections.emptyList();
        }

        // 根据 categoryIdList 查询题目分类信息
        List<CodeDuckQuestionCategory> categoryList = codeDuckQuestionCategoryService.listByIds(categoryIdList);

        // 转换为 CodeDuckQuestionCategory 列表
        List<CodeDuckQuestionCategory> categoryVOList = categoryList.stream()
                .map(this::convertToCategoryVO)
                .collect(Collectors.toList());

        return categoryVOList;
    }


    /**
     * 将 CodeDuckQuestionCategory 实体转换为 CodeDuckQuestionCategory
     *
     * @param category 题目分类实体
     * @return 题目分类视图对象
     */
    private CodeDuckQuestionCategory convertToCategoryVO(CodeDuckQuestionCategory category) {
        CodeDuckQuestionCategory vo = new CodeDuckQuestionCategory();
        BeanUtils.copyProperties(category, vo);
        return vo;
    }

}
